# -*- coding: utf-8 -*-

import os
import sys
from contextlib import closing
import time
import hashlib
import simplejson
import jinja2

import openerp
from openerp import http
from openerp.http import request
from openerp.modules.registry import RegistryManager

from openerp.addons.wechat.enterprise import WxApi, WxApplication, WxTextResponse, WxNewsResponse, WxLink, WxEmptyResponse
from reportlab.graphics.barcode import createBarcodeDrawing

SUPERUSER_ID = 1

#微信企业号消息处理类
class WxAppCrop(WxApplication):

    def __init__(self):
        #取得微信应用配置
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        ir_model_data = openerp.registry(db_name)['ir.model.data']
        with closing(db.cursor()) as cr:
            application_id = ir_model_data.xmlid_to_res_id(cr, 1, 'dzx_weixin.weixin_test_application')
            wechat_application = openerp.registry(db_name)['wechat.application']
            application = wechat_application.browse(cr, SUPERUSER_ID, application_id)
            if application:
                self.SECRET_TOKEN = application.callback_token
                self.ENCODING_AES_KEY = application.callback_aeskey
                self.APP_ID = application.application_id
                self.CORP_ID = application.dev_corpid.encode("ascii")
                self.SECRET = application.dev_secret
        self.wxapi = WxApi(self.CORP_ID, self.SECRET)


    #发送文本回调
    def on_text(self, req):
        #原样返回
        return WxTextResponse(req.Content, req)

    #进入应用回调，检查是否绑定过账号
    def on_enter_agent(self, req):
        from_username = req.FromUserName
        user_id = self.check_binding(request.session.db, from_username)
        if not user_id:
            base_url = request.httprequest.base_url
            redirect_uri = base_url + '/binding'
            binding_url = self.wxapi.authorize_url(self.CORP_ID, redirect_uri, state='("agentid":%s)' % self.APP_ID)
            link = WxLink(Title=u'账号未绑定',
                Description='绑定账号后才能进行操作, 马上绑定',
                Url = binding_url)
            return WxNewsResponse(link, req)
        else:
            return WxEmptyResponse();

    #检查账号是否已经绑定
    def check_binding(self, db_name, username):
            db = RegistryManager.get(db_name)
            with closing(db.cursor()) as cr:
                res_user = db.get('res.users')
                user_ids = res_user.search(cr, 1, [('oauth_uid', '=', username)])
                if user_ids:
                    return user_ids[0]

    #微信扫码回调
    def on_scancode_waitmsg(self, req):
        scan_type = req.ScanCodeInfo['ScanType']
        scan_result = req.ScanCodeInfo['ScanResult']
        found_sid = scan_result.find('?sid=')
        #如果扫码扫的是odoo登录的二维码
        if scan_type == 'qrcode' and found_sid > 0:
            session_md5 = scan_result[found_sid + 5:]
            from_username = req.FromUserName
            db_name = request.session.db
            db = RegistryManager.get(db_name)
            title = u'用户' + from_username + u'登录失败，请先进行账号绑定。'
            with closing(db.cursor()) as cr:
                res_user = db.get('res.users')
                user_ids = res_user.search(cr, 1, [('oauth_uid', '=', from_username)])
                if user_ids:
                    user_id = user_ids[0]
                    db_user = res_user.browse(cr, SUPERUSER_ID, user_id)
                    weixin_session = openerp.registry(db_name)['weixin.session']
                    session_ids = weixin_session.search(cr, SUPERUSER_ID, [('session_id', '=', session_md5)])
                    if session_ids:
                        session_row = weixin_session.browse(cr, SUPERUSER_ID, session_ids[0])
                        values = {'username': db_user.login,
                                    'user_id': user_id, 'oauth_uid': from_username, 'oauth_access_token': db_user.oauth_access_token,
                                    'check_time': None}
                        session_row.write(values)
                        cr.commit()
                        title = u'用户' + db_user.login + u'扫码登录成功'
            return WxTextResponse(title, req)
        else:
            return WxNewsResponse(WxLink(Title=u'扫码结果',
                Description = scan_result,
                Url = scan_result), req)


if hasattr(sys, 'frozen'):
    # When running on compiled windows binary, we don't have access to package loader.
    path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'html'))
    loader = jinja2.FileSystemLoader(path)
else:
    loader = jinja2.PackageLoader('openerp.addons.dzx_weixin', "html")

env = jinja2.Environment('<%', '%>', '${', '}', '%', loader=loader, autoescape=True)



#####################################################################
#
# 企业微信应用请求处理
#
#####################################################################
class Weixin(http.Controller):
    weixin_app = None

    def __init__(self):
        self.weixin_app = WxAppCrop()

    #微信请求处理入口
    @http.route('/weixin', auth='public')
    def weixin(self, **kw):
        result = self.weixin_app.process(request.httprequest.args, request.httprequest.data)
        return result

    #微信用户绑定
    @http.route('/weixin/binding', auth='public')
    def binding(self, **kw):
        template = env.get_template("binding.html")
        return template.render({
            'session': request.session
        })

    #微信用户绑定操作
    @http.route('/weixin/do_binding', auth='public')
    def do_binding(self, **kw):
        mobile = kw['mobile']
        auth_code = kw['auth_code']
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        partner_id = ''
        uid = ''
        login_id = ''
        oauth_access_token = ''
        if not mobile:
            return '{}'

        with closing(db.cursor()) as cr:
            res_partner = openerp.registry(db_name)['res.partner']
            mobile_partner_ids = res_partner.search(cr, SUPERUSER_ID, [('mobile', '=', mobile)])
            if mobile_partner_ids:
                partner_id = mobile_partner_ids[0]
                #根据partner找到用户
                res_users = openerp.registry(db_name)['res.users']
                users_ids = res_users.search(cr, SUPERUSER_ID, [('partner_id', '=', partner_id)])
                if users_ids:
                    user_row = res_users.browse(cr, SUPERUSER_ID, users_ids[0])
                    oauth_uid = request.session.oauth_uid
                    oauth_access_token = request.session.oauth_access_token
                    oauth_provider_id = request.session.oauth_provider_id
                    weixin_id = request.session.weixin_id
                    login_id = user_row.login
                    #写入绑定
                    user_row.write({'oauth_uid': oauth_uid, 'oauth_access_token': oauth_access_token,
                                    'oauth_provider_id': oauth_provider_id, 'mobile': mobile, 'weixin_id': weixin_id})
                    cr.commit()
                    #进行登录
                    uid = request.session.authenticate(db_name, login_id, oauth_access_token)

        #template = env.get_template("binding_result.html")
        return simplejson.dumps({'partner_id': partner_id, 'uid': uid, 'login_id': login_id,
                                 'oauth_access_token': oauth_access_token})


    #微信用户取消绑定操作
    @http.route('/weixin/do_cancel_binding', auth='user')
    def do_cancel_binding(self, **kw):
        db_name = request.session.db
        db = RegistryManager.get(db_name)
        result = ''
        with closing(db.cursor()) as cr:
            res_users = openerp.registry(db_name)['res.users']
            user_ids = res_users.search(cr, SUPERUSER_ID, [('id', '=', request.session.uid)])
            if user_ids:
                user_row = res_users.browse(cr, SUPERUSER_ID, user_ids[0])
                user_row.write({'oauth_access_token': None, 'oauth_uid': None,
                                'oauth_provider_id': None, 'mobile': None, 'weixin_id': None})
                cr.commit()
                request.session.logout(keep_db=True)
                result = 'OK'
        return simplejson.dumps({'result': result})

    #####################################################################
    #
    # 通过微信登录odoo确认页面
    # * 此页面在微信浏览器中
    #
    #####################################################################
    @http.route('/weixin/login', auth='public')
    def weixin_login_confirm(self, **kw):
        sid = kw['sid']
        oauth_uid = request.session.oauth_uid
        user_id = request.session.uid
        title = ''
        base_url = request.httprequest.base_url
        #appid: 微信SDK规定为企业的CorpID
        appid = self.weixin_app.CORP_ID
        url = self.weixin_app.wxapi.authorize_url(appid, base_url, state="('sid':'%s')" % sid)

        #如果微信中已经登录过，则提示登录成功
        if oauth_uid:
            db_name = request.session.db
            db = RegistryManager.get(db_name)
            title = u'扫码登录失败，请先进行账号绑定。'
            with closing(db.cursor()) as cr:
                res_user = db.get('res.users')
                user_ids = res_user.search(cr, 1, [('oauth_uid', '=', oauth_uid)])
                if user_ids:
                    #可能微信浏览器session失效，需要重新取得user_id
                    user_id = user_ids[0]
                    db_user = res_user.browse(cr, SUPERUSER_ID, user_id)
                    weixin_session = openerp.registry(db_name)['weixin.session']
                    session_ids = weixin_session.search(cr, SUPERUSER_ID, [('session_id', '=', sid)])
                    if session_ids:
                        session_row = weixin_session.browse(cr, SUPERUSER_ID, session_ids[0])
                        session_row.write({'username': db_user.login, 'oauth_access_token': db_user.oauth_access_token,
                                           'user_id': user_id, 'oauth_uid': oauth_uid, 'check_time': None})
                        cr.commit()
                        title = u'用户' + db_user.login + u'扫码登录成功'

        template = env.get_template("weixin_login.html")
        return template.render({
            'url': url,
            'user_id': user_id,
            'title': title
        })

    #####################################################################
    #
    # 生成session md5 二维码
    #
    #####################################################################
    @http.route('/weixin_login_qrcode', auth='public')
    def weixin_login_qrcode(self, type, value, width=600, height=100):
        """Contoller able to render barcode images thanks to reportlab.
        Samples:
            <img t-att-src="'/report/barcode/QR/%s' % o.name"/>
            <img t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s' %
                ('QR', o.name, 200, 200)"/>

        :param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
        'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
        'UPCA', 'USPS_4State'
        """
        # qr = qrcode.QRCode(
        #     version = 1,
        #     error_correction = qrcode.constants.ERROR_CORRECT_L,
        #     box_size = 10,
        #     border = 4,
        # )
        # qr.add_data('Some data')
        # qr.make(fit=True)
        #
        #
        # img = qr.make_image()

        db_name = request.session.db
        #db = openerp.registry(db_name)

        #商城用户检查
        weixin_session = openerp.registry(db_name)['weixin.session']
        registry = RegistryManager.get(db_name)
        cr = registry.cursor()
        #session_md5 = hashlib.md5()
        #session_md5.update(request.session_id)
        if not weixin_session.search(cr, SUPERUSER_ID, [('session_id', '=', value)]):
            values = {
                'session_id': value
            }
            weixin_session.create(cr, SUPERUSER_ID, values)
            cr.commit()
        cr.close()
        try:
            width, height = int(width), int(height)
            url = "http://" + request.httprequest.host + "/weixin/login?sid=" + value
            barcode = createBarcodeDrawing(
                type, value=url, format='png', width=width, height=height
            )
            barcode = barcode.asString('png')
        except (ValueError, AttributeError):
            raise exceptions.HTTPException(description='Cannot convert into barcode.')

        return request.make_response(barcode, headers=[('Content-Type', 'image/png')])

        #return img


    #####################################################################
    #
    # 每隔1秒检查是否微信登录
    #
    #####################################################################
    @http.route('/check_weixin_session', auth='public')
    def check_weixin_session(self, **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
        weixin_session = registry.get('weixin.session')
        session_md5 = hashlib.md5()
        session_md5.update(request.session_id)
        session_ids = weixin_session.search(cr, SUPERUSER_ID, [('session_id', '=', session_md5.hexdigest()), ('check_time', '=', None)])
        if session_ids:
            session_row = weixin_session.browse(cr, SUPERUSER_ID, session_ids[0])
            res_users = registry.get('res.users')
            user_ids = res_users.search(cr, SUPERUSER_ID, [('id', '=', session_row.user_id)])
            if user_ids:
                user_row = res_users.browse(cr, SUPERUSER_ID, user_ids[0])
                uid = request.session.authenticate(request.session.db, user_row.login, user_row.oauth_access_token)
                if uid is not False:
                    session_row.write({'check_time': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))})
                    cr.commit()
                    return "OK"
        return ''

    @http.route('/test/view/customer-list', auth='public')
    def customerList(self, **kw):
        db_name = request.session.db
        print '===------------ db_name:', db_name
        partner_obj = openerp.registry(db_name)['res.partner']
        #partner_obj.search()
        #print '===------------ partner_obj:', partner_obj
        template = env.get_template("customer-list.html")
        return template.render({
            'options': {},
        })

    @http.route('/test/view/<page>', auth='public')
    def index(self, page, **kw):
        template = env.get_template(page + ".html")
        return template.render({
            'options': {},
        })


    #####################################################################
    #
    # 卡券管理首页
    #
    #####################################################################
    @http.route('/wx/card/index', auth='user')
    def wx_card_index(self,  **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context
        auth_oauth_provider_obj = registry.get('auth.oauth.provider')
        provider_ids = auth_oauth_provider_obj.search(cr, SUPERUSER_ID, [('name', '=', 'weixin')])
        auth_oauth_provider = auth_oauth_provider_obj.browse(cr, SUPERUSER_ID, provider_ids[0])
        jsapi_ticket = auth_oauth_provider.jsapi_ticket

        if not jsapi_ticket:
            raise Exception(u'不能取得微信auth.oauth.provider的jsapi_ticket值')

        template = env.get_template('card/index.html')
        #appid: 微信SDK规定为企业的CorpID
        appid = self.weixin_app.CORP_ID
        timestamp = int(time.time())
        nonceStr = 'Wm3WZYTPz0wzccnW' #随机字符串
        url = request.httprequest.url
        string1 = "jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s" % (jsapi_ticket, nonceStr, timestamp, url)
        signature = hashlib.sha1(string1).hexdigest()
        return template.render({
            'appid': appid,
            'timestamp': timestamp,
            'nonceStr': nonceStr,
            'signature': signature
        })

    #####################################################################
    #
    # 卡券统计
    #
    #####################################################################
    @http.route('/wx/card/statistics', auth='user')
    def wx_card_statistics(self, **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id

        cr.execute('SELECT pci.code, pcl.is_active ' \
                           'FROM product_card_index AS pci ' \
                           'INNER JOIN product_card_line AS pcl ' \
                           'ON pci.card_line_id=pcl.id ' \
                           'INNER JOIN product_product AS pp ' \
                           'ON pp.id=pcl.product_id ' \
                           'WHERE pci.owner_id = %s  ' \
                           'ORDER BY pci.code',
                           (partner_id,))
        card_list = cr.dictfetchall()

        template = env.get_template('card/statistics.html')
        return template.render({
            'card_list': card_list,
        })

    #####################################################################
    #
    # 卡券产品汇总列表
    #
    #####################################################################
    @http.route('/wx/card/products', auth='user')
    def wx_card_products(self,  **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id
        partner_obj = registry.get('res.partner')
        #partner_dict = partner_obj.read(cr, SUPERUSER_ID, partner_id)
        partner_row = partner_obj.browse(cr, SUPERUSER_ID, partner_id)

        cr.execute('SELECT pcl.product_id, pp.name_template as product_name, COUNT(*) as card_quantity ' \
                           'FROM product_card_index AS pci ' \
                           'INNER JOIN product_card_line AS pcl ' \
                           'ON pci.card_line_id=pcl.id ' \
                           'INNER JOIN product_product AS pp ' \
                           'ON pp.id=pcl.product_id ' \
                           'WHERE pci.owner_id = %s ' \
                           'GROUP BY pcl.product_id, pp.name_template ' \
                           'ORDER BY pp.name_template',
                           (partner_id,))
        products_list = cr.dictfetchall()

        template = env.get_template('card/products.html')

        return template.render({
            "products_list": products_list,
            "partner": partner_row,

        })

    #####################################################################
    #
    # 卡券列表
    #
    #####################################################################
    @http.route('/wx/card/list', auth='user')
    def wx_card_list(self, product_id, **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id

        cr.execute('SELECT pci.code, pcl.is_active ' \
                           'FROM product_card_index AS pci ' \
                           'INNER JOIN product_card_line AS pcl ' \
                           'ON pci.card_line_id=pcl.id ' \
                           'INNER JOIN product_product AS pp ' \
                           'ON pp.id=pcl.product_id ' \
                           'WHERE pci.owner_id = %s AND pcl.product_id = %s ' \
                           'ORDER BY pci.code',
                           (partner_id, product_id))
        card_list = cr.dictfetchall()

        template = env.get_template('card/list.html')
        return template.render({
            'card_list': card_list,
        })

    #####################################################################
    #
    # 单张卡券信息
    #
    #####################################################################
    @http.route('/wx/card/line', auth='user')
    def wx_card_line(self, code, **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id

        cr.execute('SELECT pci.code, pcl.*, pp.name_template as product_name ' \
                           'FROM product_card_index AS pci ' \
                           'INNER JOIN product_card_line AS pcl ' \
                           'ON pci.card_line_id=pcl.id ' \
                           'INNER JOIN product_product AS pp ' \
                           'ON pp.id=pcl.product_id ' \
                           'WHERE pci.owner_id = %s AND pcl.code = %s ' \
                           'ORDER BY pci.code',
                           (partner_id, code))
        card_line = cr.dictfetchone()

        template = env.get_template('card/line.html')
        return template.render({
            'card_line': card_line,
        })


    #####################################################################
    #
    # 激活卡券列表提交处理
    #
    #####################################################################
    @http.route('/wx/card/submitToPay', auth='user')
    def wx_card_submitToPay(self,  **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id
        # 获得扫描的所有卡券code
        cardsList = kw['cards'].split(",")
        # 复制扫描的卡券列表 
        errorCardsList = cardsList[:]
        product_card_obj = registry.get('product.card.line')
        
        # 找到自己的有效卡券IDS
        my_card_ids = product_card_obj.search(cr, SUPERUSER_ID, [('code', 'in', cardsList),('is_active','=',False),('is_enabled','=',True),('owner_id','=',partner_id)])
        
        # 取得有效卡券的信息
        my_cards_dict = product_card_obj.read(cr, SUPERUSER_ID, my_card_ids,['code'])
        
        # 组织无效卡券信息
        for scanCard in cardsList:
            for myCard in my_cards_dict:
                if myCard['code'] == scanCard:
                    errorCardsList.remove(scanCard)
        # 获得message信息
        message_obj = registry.get('active.wizard')
        message = message_obj.get_message(cr,uid,context,my_card_ids)

        return simplejson.dumps({'message': message, 'my_active_cards':my_cards_dict , 'error_cards':errorCardsList})


    #####################################################################
    #
    # 余额支付卡券处理函数
    #
    #####################################################################
    @http.route('/wx/card/remainPay', auth='user')
    def wx_card_remainPay(self,  **kw):
        registry, cr, uid, context = request.registry, request.cr, request.session.uid, request.context

        partner_id = registry.get('res.users').browse(cr, SUPERUSER_ID, uid).partner_id.id
        
        # 获得需激活卡券的ids
        activeCardsIds = kw['activeCardIds'].split(",")
        # 字符串数组转int数组
        activeCardsIds = [ int( cardId ) for cardId in activeCardsIds if cardId ]
        
        product_card_obj = registry.get('product.card.line')
        
        # 激活卡券
        activeResult = 'fail'
        cardActiveMessage = product_card_obj.do_active(cr, SUPERUSER_ID, activeCardsIds)
        
        if len(cardActiveMessage) == 0 :
            activeResult = 'success'
        

        return simplejson.dumps({'result': activeResult, 'message':cardActiveMessage})
